在ES6中新增了let與const兩個命令,用法類似於var但是最大的不同在於var作用於全域而let與const作用於塊狀區域
中。
for(var i=0;i<5;i++){
//...
}
//即使i是宣告在for當中,卻可以在外部(全域)中呼叫到
console.log(i); // 5
for(let i=0;i<5;i++){
//...
}
//由於let只作用在塊狀區域中(for)所以在全域的環境中無法呼叫
console.log(i); //i is not defined
var a = [];
for(var i=0;i<5;i++){
a[i] = () => {
console.log(i);
}
}
a[3](); //5
由於i是透過var所建立的變數,代表著它在全域中都有效所以全域變數中只有一個變量i,
也就是說數組a中的所有成員的i都會指向同一個全域的i也就是最後一輪的i值 = 5。
var a = [];
for(let i=0;i<5;i++){
a[i] = () => {
console.log(i);
}
}
a[3](); //3
變量i是由let所宣告的所以i只對本次迴圈有效,每一次循環的i都是一個新的變量,而JaveScript引擎會記錄著上一次迴圈的值並在上一次數著基礎下進行計算,
若使用var
來宣告變數會發生變量hoisting的現象,在變量被宣告數值之前值為undefinded
,而若是使用了let或const來宣告變數一定要在宣告數值之後才能使用否則會爆錯。
//使用var宣告
console.log(foo) //undefinded
var foo = 2;
//使用let宣告
console.log(bar) //ReferenceError
let bar = 2;
在使用var去宣告變數foo會發生變數hoisting的現象,因為當程式開始運行後變量foo就存在了只是尚未給予他值,所以輸出為undefinded
;但若使用let來宣告則不會發生hoisting,代表在宣告他之前便量bar是不存在的。
只要在區塊作用域中存在let,他所宣告的變量就會綁定這個區域
不再受外面影響,而在ES6中規定了若在區塊作用域中存在let
或const
,這個區塊對這些宣告的變量就形成了封閉作用域,凡是在宣告前就使用就會爆錯。
var tmp = 123;
if(true){
tmp = "abc" //ReferenceError
let tmp; //使用let對tmp宣告會使tmp不受到外面var=123的影響
}
在過去沒有塊狀作用域的概念下,對沒有宣告的變量使用typeof去觀察他的類型都會回傳undefinded
,所以在沒有塊狀作用域之前使用typeof
是絕對安全的不會爆錯,而在ES6中倒入了let
與const
,在尚未使用let宣告變量之前使用typeof也會爆錯。
typeof x; // ReferenceError
let x;
ES6所規定的暫時性死區和let,const為了減少運行時發生錯誤而移除了變量hoisting的情況,嚴格規定先宣告再使用。
let不允許在相同作用域中重複地宣告同一個變數。
//Error
function func() {
let a = 10;
var a = 1;
}
// Error
function func() {
let a = 10;
let a = 1;
}
因此不能在函數內部重新宣告參數
func = (arg) => {
let arg;
};
func(); //Error
func = (arg) => {
{
let arg; //因為對於let arg來說已經是第二集區塊作用域,所以不符合與function相同作用域
}
};
func(); //不會出錯
const
宣告了一個唯獨的常數,一旦被宣告則常數的值變不能被改變。
const PI = 3.1415;
console.log(PI); //3.1415
PI = 3; // Assignment to constant variable.
由於const宣告的常數值不得被改變,所以在使用const宣告一個常數的時候必須立即給予他數值(初始化)不能留到後面再賦值。
const foo; //SyntaxError: Missing initializer in const declaration
而const的作用域與let相同,只有在宣告所在的塊狀作用域有效。
if (true) {
const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is not defined
const同樣不支援常數的hoisting,所以同樣存在暫時性死區,只能在宣告後使用。
if (true) {
console.log(MAX); // ReferenceError
const MAX = 5;
}
透過const所宣告的常數雖然不能更改他的值,不過他不能被更改的指的是內存的地址所保存的數據
不得被更改,對於簡單類型的數據(數值、字串、Boolen),他的值就是指向const所宣告的常數的內存地址所以不得被更動,但對於複合型數據而言(物件、陣列),保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的(總是指向固定的地址,數據結構不可變),但是數據結構內的值是可以改變的。
const foo = {};
foo.prop = 123; //對於foo這個物件中新增屬性是可以的
console.log(foo.prop) // 123
//但是不可將透過const宣告過的常數指向另一個物件
foo = {}; //TypeError: "foo" is read-only
參考資料 :
ECMAScript 6 入门